package MyFramePro.Service.Impl;

import MyFramePro.Constants.SystemConstants;
import MyFramePro.Domain.Entity.Menu;
import MyFramePro.Domain.ResponseResult;
import MyFramePro.Domain.Vo.*;
import MyFramePro.Enums.AppHttpCodeEnum;
import MyFramePro.Mapper.MenuMapper;
import MyFramePro.Service.MenuService;
import MyFramePro.Utils.BeanCopyUtils;
import MyFramePro.Utils.SecurityUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Resource
    private MenuServiceImpl menuService;

    @Resource
    private MenuMapper menuMapper;

    /**
     *  根据用户的 id 查询对应的权限信息
     */
    @Override
    public List<String> selectParmsByUserId(Long id) {

        //1.如果是管理员，则返回所有权限信息
        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();
        //如果用户id为1代表管理员，roles 中只需要有admin，permissions中需要有所有菜单类型为C或者F的，状态为正常的，未被删除的权限
        if(SecurityUtils.isAdmin()){    //id==1L
            queryWrapper.in(Menu::getMenuType, SystemConstants.MENU,SystemConstants.BUTTON);    //菜单类型为C或者F的
            queryWrapper.eq(Menu::getStatus,SystemConstants.MENU_STATUS);   //状态为正常的
            List<Menu> list = menuService.list(queryWrapper);
            List<String> permList = list.stream()
                    .map(menu -> menu.getPerms())
                    .collect(Collectors.toList());
            return permList;
        }

        //2.非管理员的用户，获取对应的权限信息
        return menuMapper.selectParmsByUserId(id);

    }


    /**
     *  查询 menus 中的信息为 tree 的形式
     */
    @Override
    public List<Menu> selectRouterMenuTreeByUserId(Long userId) {

        MenuMapper menuMapper = getBaseMapper();
        List<Menu> menus = null;
        //判断是否是管理员
        if(SecurityUtils.isAdmin()){
            //如果是 获取所有符合要求的Menu
            menus = menuMapper.selectAllRouterMenus();
        }else{
            //否则  获取当前用户所具有的Menu
            menus = menuMapper.selectNowRouterMenus(userId);
        }

        //构建tree
        //先找出第一层的菜单  然后去找他们的子菜单，设置到children属性中
        List<Menu> menuTree = builderMenuTree(menus,0L);
        return menuTree;
    }



    private List<Menu> builderMenuTree(List<Menu> menus, Long parentId) {
        List<Menu> menuTree = menus.stream()
                .filter(menu -> menu.getParentId().equals(parentId))
                .map(new Function<Menu, Menu>() {
                    @Override
                    public Menu apply(Menu menu) {

                        return menu.setChildren(getChildren(menu,menus));
                    }
                })
                .collect(Collectors.toList());
        return menuTree;
    }


    /**
     * 获取存入参数的 子Menu集合
     */
    private List<Menu> getChildren(Menu menu, List<Menu> menus) {
        List<Menu> childrenList = menus.stream()
                .filter(m -> m.getParentId().equals(menu.getId()))
                .map(m->m.setChildren(getChildren(m,menus)))
                .collect(Collectors.toList());
        return childrenList;
    }


    /**
     * 这里是展示菜单列表的功能
     */
    @Override
    public ResponseResult getMenuList(String status, String menuName) {

        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();

        if(StringUtils.hasText(status)) {      //若查询状态的条件不存在，则默认查询状态正常的菜单列表
            queryWrapper.eq(Menu::getStatus, status);
        }else {
            queryWrapper.eq(Menu::getStatus,SystemConstants.MENU_STATUS);
        }

        queryWrapper.like(StringUtils.hasText(menuName),Menu::getMenuName,menuName);
        queryWrapper.orderByAsc(Menu::getParentId).orderByAsc(Menu::getOrderNum);

        List<Menu> menuList = menuService.list(queryWrapper);

        List<MenuVo> menuVos = BeanCopyUtils.myCopyBeanList(menuList, MenuVo.class);

        return ResponseResult.okResult(menuVos);
    }


    /**
     * 这里是新增菜单的功能
     */
    @Override
    public ResponseResult addMenu(Menu menu) {

        menuService.save(menu);

        return ResponseResult.okResult();
    }


    /**
     * 这里是根据 ID 查询对应的菜单数据的功能
     */
    @Override
    public ResponseResult getMenu(Long id) {

        Menu menu = menuService.getById(id);

        MenuVo menuVo = BeanCopyUtils.myCopyBean(menu, MenuVo.class);

        return ResponseResult.okResult(menuVo);
    }


    /**
     * 这里是更新菜单的功能
     */
    @Override
    public ResponseResult updateMenu(Menu menu) {

        //1.能够修改菜单，但是修改的时候不能把父菜单设置为当前菜单
        if(!menu.getId().equals(menu.getParentId())) {

            menuService.updateById(menu);
        }else {
            //2.如果设置了需要给出相应的提示，并且修改失败
            return ResponseResult.errorResult(AppHttpCodeEnum.MENU_UPDATE_ERROR);
        }

        return ResponseResult.okResult();
    }


    /**
     * 这里是删除菜单的功能
     */
    @Override
    public ResponseResult deleteMenu(Long menuId) {

        LambdaQueryWrapper<Menu> queryWrapper = new LambdaQueryWrapper<>();

        //1.能够删除菜单，但是如果要删除的菜单有子菜单则提示：
        queryWrapper.eq(Menu::getParentId,menuId);

        List<Menu> menus = menuService.list(queryWrapper);  //将当前菜单ID 当作 父级 ID 进行查询，若有数据，则表示存在子菜单


        if(null==menus||menus.size()==0) {  //判断查询的集合是否为空

            menuService.removeById(menuId);
        }else {

            //2.存在子菜单不允许删除 并且删除失败
            return ResponseResult.errorResult(AppHttpCodeEnum.MENU_DELETE_ERROR);
        }

        return ResponseResult.okResult();
    }



    /******************************************************************************************************************
     * 这里是新增角色功能，中的获取菜单树的功能
     */
    @Override
    public List<BehindMenuTreeVo> selectMenuTrees() {

        //1.查询所有的菜单的信息
        List<BehindMenuTreeVo> menuTreeVos = menuMapper.selectMenus();

        //2.构建 tree ，先找出第一层的菜单，然后再找对应的子菜单传入到 children 中
        List<BehindMenuTreeVo> menuTreeVoList = buildBehindMenutree(menuTreeVos,0L);

        return menuTreeVoList;
    }

    /**
     * 这里进行构建 MenuTree
     * @param menuTreeVos   所有的菜单信息
     * @param parentId  传入的父级 ID
     */
    private List<BehindMenuTreeVo> buildBehindMenutree(List<BehindMenuTreeVo> menuTreeVos, long parentId) {

        List<BehindMenuTreeVo> behindMenuTree = menuTreeVos.stream()
                //1.找出第一层菜单信息
                .filter(behindMenuTreeVo -> behindMenuTreeVo.getParentId().equals(parentId))    //这里设置过滤语句，进行条件过滤
                .map(new Function<BehindMenuTreeVo, BehindMenuTreeVo>() {
                    @Override
                    public BehindMenuTreeVo apply(BehindMenuTreeVo behindMenuTreeVo) {

                        //这里进行构建父级的子级菜单信息
                        return behindMenuTreeVo.setChildren(getBehindChildren(behindMenuTreeVo, menuTreeVos));
                    }
                }).collect(Collectors.toList());

        return behindMenuTree;
    }


    /**
     * 获取存入参数的 子Menu集合 (Children)
     */
    private List<BehindMenuTreeVo> getBehindChildren(BehindMenuTreeVo menuTreeVo, List<BehindMenuTreeVo> menuTreeVos) {

        List<BehindMenuTreeVo> behindMenuTreeVos = menuTreeVos.stream()
                .filter(new Predicate<BehindMenuTreeVo>() {
                    @Override
                    public boolean test(BehindMenuTreeVo behindMenuTreeVo) {

                        //这里根据父级 ID 与子级 ID 的关联，获取父级下对应的子级
                        return behindMenuTreeVo.getParentId().equals(menuTreeVo.getId());   //注意这里是 子级parentId 与 父级id 关联
                    }
                })
                //这里进行构建父级的子级菜单信息，套娃，直到没有的父级 ID 所对应的子级
                .map(behindMenuTreeVo -> behindMenuTreeVo.setChildren(getBehindChildren(behindMenuTreeVo, menuTreeVos)))
                .collect(Collectors.toList());

        return behindMenuTreeVos;
    }


    /******************************************************************************************************************
     * 修改角色之   加载对应角色菜单列表树接口
     */
    @Override
    public ResponseResult getRoleMenuTree(Long roleId) {

        //1.根据 ID 查询对应的菜单信息
        List<BehindMenuTreeVo>  menuTreeVos = menuMapper.selectRoleMenu(roleId);

        List<BehindMenuTreeVo> behindMenuTreeVos = menuMapper.selectMenus();    //所有的菜单信息

        List<Long> menuIds = menuTreeVos.stream()   //这里是对应角色，之前已经选择的菜单 ID
                .map(new Function<BehindMenuTreeVo, Long>() {
                    @Override
                    public Long apply(BehindMenuTreeVo behindMenuTreeVo) {

                        return behindMenuTreeVo.getId();
                    }
                })
                .collect(Collectors.toList());

        //2.首先找出第一层爷爷级菜单信息，然后再获取对应的 children 构建 tree
        List<BehindMenuTreeVo> menuTreeVoList = buildBehindMenutree(behindMenuTreeVos,0L);

        return ResponseResult.okResult(new BehindRoleMenuVo(menuTreeVoList,menuIds));
    }


    /**
     * 这里进行构建 MenuTree
     * @param menuTreeVos   所有的菜单信息
     * @param parentId  传入的父级 ID
     */
    private List<BehindMenuTreeVo> buildBehindRoleMenuTree(List<BehindMenuTreeVo> menuTreeVos, Long parentId) {

        List<BehindMenuTreeVo> behindMenuTreeVos = menuTreeVos.stream()
                .filter(behindMenuTreeVo -> behindMenuTreeVo.getParentId().equals(parentId))    //条件过滤
                .map(new Function<BehindMenuTreeVo, BehindMenuTreeVo>() {
                    @Override
                    public BehindMenuTreeVo apply(BehindMenuTreeVo behindMenuTreeVo) {

                        return behindMenuTreeVo.setChildren(getBehindChildren(behindMenuTreeVo, menuTreeVos));
                    }
                }).collect(Collectors.toList());

        return behindMenuTreeVos;
    }


}
